This invention relates to initialization of electronic systems having multiple programmable processors.
The process of starting, or booting up, an electronic system having a programmable processor connected to one or more memory devices for storing program instructions, or code, and data is not as simple as it might seem at first glance. An important part of the reason for this is the need for the processor to begin operation in a well-defined state.
The traditional ways of loading program code and data to a bare system are either by “pushing” the code and data into the system's random-access memory (RAM) directly or by using a bootloader. The bootloader, which is sometimes called a boot loader or a bootstrap loader, is a set of instructions (i.e., program code, sometimes called “boot code”) that can be either “pushed” into the system's RAM or loaded into the RAM from a non-volatile memory, such as read-only memory (ROM). In its execution by the processor, the bootloader then “drags” in the rest of the code and data and starts the system.
Examples of prior mechanisms for starting processor systems, including bootloaders, are U.S. Pat. No. 5,652,886 to Tulpule et al. and U.S. Pat. No. 6,490,722 to Barton et al. and U.S. Patent Application Publication No. US 2002/0138156 A1 to Wong et al. Barton et al., for example, describes a two-stage bootloader in which the second stage finds, verifies, and loads the operating system. In Wong et al., a multiprocessor system uses a master processor coupled to a ROM to transfer boot code to slave processors, with memory controllers in the slave processors denying memory access requests until the boot code has been transferred to their RAMs.
As indicated by Barton et al. and Wong et al., for example, starting up a multi-processor system, which can be generally considered as having a master or host processor, i.e., the system that orders the boot, and one or more slave or client processors, i.e., the system to be booted, is even more complicated than starting up a single-processor system.
Advantages of the “push” method are that it requires no code to execute in the slave during boot and that the only synchronization required is to hold the slave in a reset state and release it when loading is finished. Nevertheless, the “push” method works only when the memory or memories of the slave are visible to the host. This visibility can be implemented in several ways. For example, a memory may be visible on the address and data busses of both the host and the slave processors or direct memory access (DMA) transfers may be allowed from the host's memory or memories to the slave's memory or memories.
When the slave's memory to be loaded is invisible to the host, the “push” method cannot be used. In that situation, some form of bootloading must be used. As noted above, the bootloader technique requires either that boot code can be pushed onto the slave (which in this case is not possible) or that the slave can load code from a non-volatile memory. The bootloader then initiates a transfer of code from the host to the slave and finishes loading the memory.
Multi-processor systems in which some or all of a slave's memory is not visible to a host are possible. In such systems, it can be advantageous to take advantage of well-established software frameworks for loading and inter-processor communication, which render traditional bootloaders undesirable. Moreover, a bootloader can conflict with the operating system, which can be said to want to have control over the entire system and all of the memory.
Among the problems faced when integrating a bootloader with an operating system (OS) are ensuring that code that is not yet loaded is not executed, efficiently loading code to a memory or memories invisible to the host, and synchronizing with the host the loading and booting of the slave(s). Moreover, it is necessary to determine which portions of the system must be loaded to memories visible to both host and slave processors and how the binary image to be loaded should be arranged for the bootloader to work together with the OS. Another issue that can be important is the integration of the bootloader and the OS, as an already established framework for communication between host and slave then can be used during loading. Such a framework typically would include one or more primitives for communication that rely on OS-features.